package org.example.compare.schedule;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import org.example.compare.dto.*;

import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.nio.file.Files;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 测试数据生成器类，用于为calculateItem_4函数生成测试数据
 * 该函数使用到的非函数参数列表外部变量包括:
 * 1. hProcessSet - 需要进行排产的工序集
 * 2. sPositionsScore - 可以排产的工位
 * 3. hScoreByProcess - 按工序查找的分数表
 * 4. SchData.orderId2Order - 订单映射表
 * 5. SchData.pPositionDtos - 工位数据
 */
public class CalculateItem4TestDataGenerator {

    private static final ObjectMapper objectMapper = new ObjectMapper();
    private static final Random random = new Random();

    static {
        objectMapper.registerModule(new JavaTimeModule());
        objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
        objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
    }

    /**
     * 生成随机测试数据并保存到文件
     */
    public static void generateRandomTestData(int iteration) throws IOException {
        String basePath = "../../test_data/calculateItem_4/random_case_" + iteration;
        File baseDir = new File(basePath);

        // 清空文件夹
        clearDirectory(baseDir);

        if (!baseDir.exists()) {
            baseDir.mkdirs();
        }

        // 生成测试数据
        Map<String, OrderDto> orderId2Order = generateOrderId2OrderData(basePath);
        Map<Long, PositionDto> pPositionDtos = generatePositionDtosData(basePath);
        Map<Long, OrderProcess> hProcessSet = generateProcessSetData(basePath, orderId2Order);
        Set<Long> sPositionsScore = generatePositionScoreData(basePath);
        generateScoreByProcessData(basePath, hProcessSet, sPositionsScore);
        generateFunctionParams(basePath);
    }

    /**
     * 生成手动测试数据并保存到文件
     */
    public static void generateManualTestData(int caseNumber) throws IOException {
        String basePath = "../../test_data/calculateItem_4/manual_case_" + caseNumber;
        File baseDir = new File(basePath);

        // 清空文件夹
        clearDirectory(baseDir);

        if (!baseDir.exists()) {
            baseDir.mkdirs();
        }

        if (caseNumber == 1) {
            generateManualTestCase1(basePath);
        } else if (caseNumber == 2) {
            generateManualTestCase2(basePath);
        }
    }

    /**
     * 生成手动测试案例1
     */
    private static void generateManualTestCase1(String basePath) throws IOException {
        // 生成订单数据
        Map<String, OrderDto> orderId2Order = new HashMap<>();

        // 订单1
        OrderDto order1 = OrderDto.InitOrder();
        order1.setMLocalOrderNum("ORDER001");
        order1.setMColor("红色");
        order1.setMLineColorNum("LINE001");
        order1.setMOuterOrderNum("OUTER001");
        orderId2Order.put(order1.getMLocalOrderNum(), order1);

        // 订单2
        OrderDto order2 = OrderDto.InitOrder();
        order2.setMLocalOrderNum("ORDER002");
        order2.setMColor("蓝色");
        order2.setMLineColorNum("LINE001"); // 同一条线
        order2.setMOuterOrderNum("OUTER002");
        orderId2Order.put(order2.getMLocalOrderNum(), order2);

        // 保存到文件
        objectMapper.writeValue(new File(basePath + "/orderId2Order.json"), orderId2Order);

        // 生成工位数据
        Map<Long, PositionDto> pPositionDtos = new HashMap<>();
        PositionDto position1 = new PositionDto();
        position1.setPositionId(10001L);
        position1.setMBoxInPro(""); // 设置为空字符串而不是null
        position1.setMBoxWaitingForPro(""); // 设置为空字符串而不是null
        pPositionDtos.put(10001L, position1);

        PositionDto position2 = new PositionDto();
        position2.setPositionId(10002L);
        position2.setMBoxInPro(""); // 设置为空字符串而不是null
        position2.setMBoxWaitingForPro(""); // 设置为空字符串而不是null
        pPositionDtos.put(10002L, position2);

        PositionDto position3 = new PositionDto();
        position3.setPositionId(10003L);
        position3.setMBoxInPro(""); // 设置为空字符串而不是null
        position3.setMBoxWaitingForPro(""); // 设置为空字符串而不是null
        pPositionDtos.put(10003L, position3);

        // 保存到文件
        objectMapper.writeValue(new File(basePath + "/pPositionDtos.json"), pPositionDtos);

        // 生成工序集数据
        Map<Long, OrderProcess> hProcessSet = new HashMap<>();

        // 工序1 (属于订单1)
        OrderProcess process1 = OrderProcess.InitOrderProcess(order1);
        process1.setOrderProcessId(1001L);
        process1.setMProcessType("缝制");

        ProcessSch scheduling1 = new ProcessSch();
        scheduling1.setMbHoldFlag(false);
        scheduling1.setMbNGFlag(false);
        
        // 可做此工序的工位
        Set<Long> posCanDo1 = new HashSet<>();
        posCanDo1.add(10001L);
        posCanDo1.add(10002L);
        scheduling1.setMPosCanDo(posCanDo1);
        
        // 正在工作的工位
        Set<Long> isWorkingPos1 = new HashSet<>();
        isWorkingPos1.add(10001L); // 10001号工位正在工作
        scheduling1.setMisWorkingPos(isWorkingPos1);

        process1.setMScheduling(scheduling1);
        hProcessSet.put(1001L, process1);

        // 工序2 (属于订单2)
        OrderProcess process2 = OrderProcess.InitOrderProcess(order2);
        process2.setOrderProcessId(1002L);
        process2.setMProcessType("缝制");

        ProcessSch scheduling2 = new ProcessSch();
        scheduling2.setMbHoldFlag(false);
        scheduling2.setMbNGFlag(false);
        
        // 可做此工序的工位
        Set<Long> posCanDo2 = new HashSet<>();
        posCanDo2.add(10002L);
        posCanDo2.add(10003L);
        scheduling2.setMPosCanDo(posCanDo2);
        
        // 正在工作的工位
        Set<Long> isWorkingPos2 = new HashSet<>();
        isWorkingPos2.add(10002L); // 10002号工位正在工作
        scheduling2.setMisWorkingPos(isWorkingPos2);

        process2.setMScheduling(scheduling2);
        hProcessSet.put(1002L, process2);

        // 保存到文件
        objectMapper.writeValue(new File(basePath + "/hProcessSet.json"), hProcessSet);

        // 生成可以排产的工位数据
        Set<Long> sPositionsScore = new HashSet<>();
        sPositionsScore.add(10001L);
        sPositionsScore.add(10002L);
        sPositionsScore.add(10003L);

        // 保存到文件
        objectMapper.writeValue(new File(basePath + "/sPositionsScore.json"), sPositionsScore);

        // 生成按工序查找的分数表数据
        Map<Long, List<Score>> hScoreByProcess = new HashMap<>();

        // 工序1的分数
        List<Score> scores1 = new ArrayList<>();
        Score score1_1 = new Score();
        score1_1.setPositionId(10001L);
        score1_1.setTotal(80.0);
        double[] scoreItems1 = new double[20];
        score1_1.setScoreItem(scoreItems1);
        scores1.add(score1_1);

        Score score1_2 = new Score();
        score1_2.setPositionId(10002L);
        score1_2.setTotal(75.0);
        double[] scoreItems2 = new double[20];
        score1_2.setScoreItem(scoreItems2);
        scores1.add(score1_2);

        hScoreByProcess.put(1001L, scores1);

        // 工序2的分数
        List<Score> scores2 = new ArrayList<>();
        Score score2_1 = new Score();
        score2_1.setPositionId(10002L);
        score2_1.setTotal(60.0);
        double[] scoreItems3 = new double[20];
        score2_1.setScoreItem(scoreItems3);
        scores2.add(score2_1);

        Score score2_2 = new Score();
        score2_2.setPositionId(10003L);
        score2_2.setTotal(55.0);
        double[] scoreItems4 = new double[20];
        score2_2.setScoreItem(scoreItems4);
        scores2.add(score2_2);

        hScoreByProcess.put(1002L, scores2);

        // 保存到文件
        objectMapper.writeValue(new File(basePath + "/hScoreByProcess.json"), hScoreByProcess);

        // 生成函数参数
        Map<String, Object> functionParams = new HashMap<>();
        functionParams.put("ratio", 1.0);

        // 保存到文件
        objectMapper.writeValue(new File(basePath + "/testCases.json"), functionParams);
    }

    /**
     * 生成手动测试案例2
     */
    private static void generateManualTestCase2(String basePath) throws IOException {
        // 生成订单数据
        Map<String, OrderDto> orderId2Order = new HashMap<>();

        // 订单1
        OrderDto order1 = OrderDto.InitOrder();
        order1.setMLocalOrderNum("ORDER003");
        order1.setMColor("绿色");
        order1.setMLineColorNum("LINE002");
        order1.setMOuterOrderNum("OUTER003");
        orderId2Order.put(order1.getMLocalOrderNum(), order1);

        // 订单2
        OrderDto order2 = OrderDto.InitOrder();
        order2.setMLocalOrderNum("ORDER004");
        order2.setMColor("绿色"); // 相同颜色
        order2.setMLineColorNum("LINE003");
        order2.setMOuterOrderNum("OUTER004");
        orderId2Order.put(order2.getMLocalOrderNum(), order2);

        // 保存到文件
        objectMapper.writeValue(new File(basePath + "/orderId2Order.json"), orderId2Order);

        // 生成工位数据
        Map<Long, PositionDto> pPositionDtos = new HashMap<>();
        PositionDto position1 = new PositionDto();
        position1.setPositionId(20001L);
        position1.setMBoxInPro(""); // 设置为空字符串而不是null
        position1.setMBoxWaitingForPro(""); // 设置为空字符串而不是null
        pPositionDtos.put(20001L, position1);

        PositionDto position2 = new PositionDto();
        position2.setPositionId(20002L);
        position2.setMBoxInPro(""); // 设置为空字符串而不是null
        position2.setMBoxWaitingForPro(""); // 设置为空字符串而不是null
        pPositionDtos.put(20002L, position2);

        PositionDto position3 = new PositionDto();
        position3.setPositionId(20003L);
        position3.setMBoxInPro(""); // 设置为空字符串而不是null
        position3.setMBoxWaitingForPro(""); // 设置为空字符串而不是null
        pPositionDtos.put(20003L, position3);

        // 保存到文件
        objectMapper.writeValue(new File(basePath + "/pPositionDtos.json"), pPositionDtos);

        // 生成工序集数据
        Map<Long, OrderProcess> hProcessSet = new HashMap<>();

        // 工序1 (属于订单1)
        OrderProcess process1 = OrderProcess.InitOrderProcess(order1);
        process1.setOrderProcessId(1003L);
        process1.setMProcessType("熨烫");

        ProcessSch scheduling1 = new ProcessSch();
        scheduling1.setMbHoldFlag(false);
        scheduling1.setMbNGFlag(false);
        
        // 可做此工序的工位
        Set<Long> posCanDo1 = new HashSet<>();
        posCanDo1.add(20001L);
        posCanDo1.add(20002L);
        scheduling1.setMPosCanDo(posCanDo1);
        
        // 正在工作的工位
        Set<Long> isWorkingPos1 = new HashSet<>();
        isWorkingPos1.add(20001L); // 20001号工位正在工作
        scheduling1.setMisWorkingPos(isWorkingPos1);

        process1.setMScheduling(scheduling1);
        hProcessSet.put(1003L, process1);

        // 工序2 (属于订单2)
        OrderProcess process2 = OrderProcess.InitOrderProcess(order2);
        process2.setOrderProcessId(1004L);
        process2.setMProcessType("包装");

        ProcessSch scheduling2 = new ProcessSch();
        scheduling2.setMbHoldFlag(false);
        scheduling2.setMbNGFlag(false);
        
        // 可做此工序的工位
        Set<Long> posCanDo2 = new HashSet<>();
        posCanDo2.add(20002L);
        posCanDo2.add(20003L);
        scheduling2.setMPosCanDo(posCanDo2);
        
        // 正在工作的工位为空
        Set<Long> isWorkingPos2 = new HashSet<>();
        scheduling2.setMisWorkingPos(isWorkingPos2);

        process2.setMScheduling(scheduling2);
        hProcessSet.put(1004L, process2);

        // 保存到文件
        objectMapper.writeValue(new File(basePath + "/hProcessSet.json"), hProcessSet);

        // 生成可以排产的工位数据
        Set<Long> sPositionsScore = new HashSet<>();
        sPositionsScore.add(20001L);
        sPositionsScore.add(20002L);
        sPositionsScore.add(20003L);

        // 保存到文件
        objectMapper.writeValue(new File(basePath + "/sPositionsScore.json"), sPositionsScore);

        // 生成按工序查找的分数表数据
        Map<Long, List<Score>> hScoreByProcess = new HashMap<>();

        // 工序1的分数
        List<Score> scores1 = new ArrayList<>();
        Score score1_1 = new Score();
        score1_1.setPositionId(20001L);
        score1_1.setTotal(90.0);
        double[] scoreItems1 = new double[20];
        score1_1.setScoreItem(scoreItems1);
        scores1.add(score1_1);

        Score score1_2 = new Score();
        score1_2.setPositionId(20002L);
        score1_2.setTotal(85.0);
        double[] scoreItems2 = new double[20];
        score1_2.setScoreItem(scoreItems2);
        scores1.add(score1_2);

        hScoreByProcess.put(1003L, scores1);

        // 工序2的分数
        List<Score> scores2 = new ArrayList<>();
        Score score2_1 = new Score();
        score2_1.setPositionId(20002L);
        score2_1.setTotal(70.0);
        double[] scoreItems3 = new double[20];
        score2_1.setScoreItem(scoreItems3);
        scores2.add(score2_1);

        Score score2_2 = new Score();
        score2_2.setPositionId(20003L);
        score2_2.setTotal(65.0);
        double[] scoreItems4 = new double[20];
        score2_2.setScoreItem(scoreItems4);
        scores2.add(score2_2);

        hScoreByProcess.put(1004L, scores2);

        // 保存到文件
        objectMapper.writeValue(new File(basePath + "/hScoreByProcess.json"), hScoreByProcess);

        // 生成函数参数
        Map<String, Object> functionParams = new HashMap<>();
        functionParams.put("ratio", 0.8);

        // 保存到文件
        objectMapper.writeValue(new File(basePath + "/testCases.json"), functionParams);
    }

    /**
     * 生成订单映射表数据
     */
    private static Map<String, OrderDto> generateOrderId2OrderData(String basePath) throws IOException {
        Map<String, OrderDto> orderId2Order = new HashMap<>();

        int orderCount = 5 + random.nextInt(6); // 5-10个订单
        String[] colors = {"红色", "蓝色", "绿色", "黄色", "紫色"};
        String[] lineNumbers = {"LINE001", "LINE002", "LINE003", "LINE004", "LINE005"};
        String[] outerNumbers = {"OUTER001", "OUTER002", "OUTER003", "OUTER004", "OUTER005"};

        for (int i = 0; i < orderCount; i++) {
            OrderDto order = OrderDto.InitOrder();
            order.setMLocalOrderNum("ORDER" + String.format("%03d", i+1));
            order.setMColor(colors[random.nextInt(colors.length)]);
            order.setMLineColorNum(lineNumbers[random.nextInt(lineNumbers.length)]);
            order.setMOuterOrderNum(outerNumbers[random.nextInt(outerNumbers.length)]);
            
            // 使用订单编号作为键
            orderId2Order.put(order.getMLocalOrderNum(), order);
        }

        // 保存到文件
        objectMapper.writeValue(new File(basePath + "/orderId2Order.json"), orderId2Order);

        return orderId2Order;
    }

    /**
     * 生成工位数据
     */
    private static Map<Long, PositionDto> generatePositionDtosData(String basePath) throws IOException {
        Map<Long, PositionDto> pPositionDtos = new HashMap<>();

        int positionCount = 20 + random.nextInt(21); // 20-40个工位
        for (int i = 0; i < positionCount; i++) {
            long positionId = 10000L + random.nextInt(100); // 工位编号 10000-10099
            PositionDto positionDto = new PositionDto();
            positionDto.setPositionId(positionId);
            // 随机设置工位状态
            int[] statusOptions = {0, 1, 2, 3, 4}; // 对应各种工位状态
            positionDto.setMiPosStatus(statusOptions[random.nextInt(statusOptions.length)]);
            // 设置默认的筐号为空字符串而不是null
            positionDto.setMBoxInPro("");
            positionDto.setMBoxWaitingForPro("");
            pPositionDtos.put(positionId, positionDto);
        }

        // 保存到文件
        objectMapper.writeValue(new File(basePath + "/pPositionDtos.json"), pPositionDtos);

        return pPositionDtos;
    }

    /**
     * 生成工序集数据
     */
    private static Map<Long, OrderProcess> generateProcessSetData(String basePath, Map<String, OrderDto> orderId2Order) throws IOException {
        Map<Long, OrderProcess> hProcessSet = new HashMap<>();
        List<String> orderIds = new ArrayList<>(orderId2Order.keySet());
        String[] processTypes = {"缝制", "熨烫", "包装", "质检", ""};

        int processCount = 10 + random.nextInt(11); // 10-20个工序
        for (int i = 0; i < processCount; i++) {
            OrderDto order = orderId2Order.get(orderIds.get(random.nextInt(orderIds.size())));
            OrderProcess process = OrderProcess.InitOrderProcess(order);
            process.setOrderProcessId((long) (1000 + i));
            process.setMProcessType(processTypes[random.nextInt(processTypes.length)]);

            ProcessSch scheduling = new ProcessSch();
            scheduling.setMbHoldFlag(random.nextBoolean() && random.nextBoolean()); // 25%概率为true
            scheduling.setMbNGFlag(random.nextBoolean() && random.nextBoolean() && random.nextBoolean()); // 12.5%概率为true
            
            // 生成可做此工序的工位
            Set<Long> posCanDo = new HashSet<>();
            int posCount = 2 + random.nextInt(4); // 2-5个工位
            for (int j = 0; j < posCount; j++) {
                posCanDo.add((long) (10000 + random.nextInt(100))); // 工位编号 10000-10099
            }
            scheduling.setMPosCanDo(posCanDo);
            
            // 生成正在工作的工位
            Set<Long> isWorkingPos = new HashSet<>();
            if (!posCanDo.isEmpty()) {
                List<Long> posList = new ArrayList<>(posCanDo);
                int workingPosCount = random.nextInt(Math.min(posList.size() + 1, 3)); // 0-2个工位正在工作
                for (int j = 0; j < workingPosCount; j++) {
                    isWorkingPos.add(posList.get(random.nextInt(posList.size())));
                }
            }
            scheduling.setMisWorkingPos(isWorkingPos);

            process.setMScheduling(scheduling);
            hProcessSet.put(process.getOrderProcessId(), process);
        }

        // 保存到文件
        objectMapper.writeValue(new File(basePath + "/hProcessSet.json"), hProcessSet);

        return hProcessSet;
    }

    /**
     * 生成可以排产的工位数据
     */
    private static Set<Long> generatePositionScoreData(String basePath) throws IOException {
        Set<Long> sPositionsScore = new HashSet<>();

        int positionCount = 20 + random.nextInt(21); // 20-40个工位
        for (int i = 0; i < positionCount; i++) {
            sPositionsScore.add((long) (10000 + random.nextInt(100))); // 工位编号 10000-10099
        }

        // 保存到文件
        objectMapper.writeValue(new File(basePath + "/sPositionsScore.json"), sPositionsScore);

        return sPositionsScore;
    }

    /**
     * 生成按工序查找的分数表数据
     */
    private static void generateScoreByProcessData(String basePath, Map<Long, OrderProcess> hProcessSet, Set<Long> sPositionsScore) throws IOException {
        Map<Long, List<Score>> hScoreByProcess = new HashMap<>();
        List<Long> positionList = new ArrayList<>(sPositionsScore);

        for (Map.Entry<Long, OrderProcess> entry : hProcessSet.entrySet()) {
            Long processId = entry.getKey();
            OrderProcess process = entry.getValue();
            
            List<Score> scores = new ArrayList<>();
            
            // 为每个可做此工序的工位生成分数
            Set<Long> posCanDo = process.getMScheduling().getMPosCanDo();
            if (posCanDo != null && !posCanDo.isEmpty()) {
                for (Long positionId : posCanDo) {
                    // 只有当工位在可排产工位列表中时才生成分数
                    if (sPositionsScore.contains(positionId)) {
                        Score score = new Score();
                        score.setPositionId(positionId);
                        // 总分保留两位小数
                        double total = random.nextDouble() * 100; // 0-100的随机分数
                        total = new BigDecimal(total).setScale(2, RoundingMode.HALF_UP).doubleValue();
                        score.setTotal(total);
                        
                        // 初始化分数项数组，每项保留两位小数
                        double[] scoreItems = new double[20];
                        for (int i = 0; i < scoreItems.length; i++) {
                            double item = random.nextDouble() * 10; // 0-10的随机分数项
                            item = new BigDecimal(item).setScale(2, RoundingMode.HALF_UP).doubleValue();
                            scoreItems[i] = item;
                        }
                        score.setScoreItem(scoreItems);
                        
                        scores.add(score);
                    }
                }
            }
            
            hScoreByProcess.put(processId, scores);
        }

        // 保存到文件
        objectMapper.writeValue(new File(basePath + "/hScoreByProcess.json"), hScoreByProcess);
    }

    /**
     * 生成函数参数
     */
    private static void generateFunctionParams(String basePath) throws IOException {
        Map<String, Object> functionParams = new HashMap<>();
        // ratio值保留两位小数
        double ratio = random.nextDouble() * 2; // 0-2之间的随机比例
        ratio = new BigDecimal(ratio).setScale(2, RoundingMode.HALF_UP).doubleValue();
        functionParams.put("ratio", ratio);

        // 保存到文件
        objectMapper.writeValue(new File(basePath + "/testCases.json"), functionParams);
    }

    /**
     * 清空目录
     */
    private static void clearDirectory(File directory) throws IOException {
        if (directory.exists()) {
            Files.walk(directory.toPath())
                    .sorted(Comparator.reverseOrder())
                    .map(java.nio.file.Path::toFile)
                    .forEach(File::delete);
        }
    }

    /**
     * 主函数，用于生成测试数据
     */
    public static void main(String[] args) {
        try {
            // 生成50个随机测试案例
            for (int i = 1; i <= 50; i++) {
                generateRandomTestData(i);
                System.out.println("随机测试案例 " + i + " 生成成功");
            }

            // 生成2个手动测试案例
            generateManualTestData(1);
            System.out.println("手动测试案例 1 生成成功");
            
            generateManualTestData(2);
            System.out.println("手动测试案例 2 生成成功");

            System.out.println("所有测试数据生成完毕！");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}